package com.manong.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.manong.dao.DepartmentMapper;
import com.manong.dao.SysFinancialExpensesMapper;
import com.manong.entity.Department;
import com.manong.entity.SysFinancialExpenses;
import com.manong.service.SysFinancialExpensesService;
import com.manong.vo.CommonReqVo;
import com.manong.vo.SysFinancialExpensesVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 财务支出(SysFinancialExpenses)表服务实现类
 *
 */
@Service("sysFinancialExpensesService")
public class SysFinancialExpensesServiceImpl extends ServiceImpl<SysFinancialExpensesMapper, SysFinancialExpenses> implements SysFinancialExpensesService {

    @Resource
    private DepartmentMapper departmentMapper;

    @Override
    public IPage listAll(CommonReqVo commonReqVo) {
        //分页操作
        IPage<SysFinancialExpenses> page = new Page<SysFinancialExpenses>(commonReqVo.getPageNo(),
                commonReqVo.getPageSize());
        // 条件构造器，便于 为查询添加查询条件的
        LambdaQueryWrapper<SysFinancialExpenses> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 如果传入的 字段 key 不为空，就添加一个 模糊查询条件
        // 这里会根据 notes 字段模糊查询，如果 key=adc 则 会在生成的sql后加上 where notes like '%adc%'
        lambdaQueryWrapper.like(StringUtils.isNotBlank(commonReqVo.getKey()),
                SysFinancialExpenses::getNotes, commonReqVo.getKey());
        // 进行分页查询
        final IPage<SysFinancialExpenses> page1 = this.page(page, lambdaQueryWrapper);
        // 这是查询所有部门数据，因为 SysFinancialExpenses中不存储 部门名称， 是根据部门id 进行外键关联的，
        //所以返回给前端的时候需要把部门名称也返回给前端
        final List<Department> departments = departmentMapper.selectList(null);
        // 拿到 分页查询结果中的数据集合
        final List<SysFinancialExpenses> records = page1.getRecords();
        IPage<SysFinancialExpensesVo> sysFinancialExpensesVoIPage = new Page<>();
        // 这是 拷贝属性，因为 IPage<SysFinancialExpenses> 中 只有部门id字段，没有部门名称字段，
        // 而返回给前端的时候需要部门名称，所以新创建一个对象，包含部门名称
        BeanUtils.copyProperties(page1, sysFinancialExpensesVoIPage);
        List<SysFinancialExpensesVo> sysFinancialExpensesVos = new ArrayList<>();
//        这里是 for循环每个分页结果中的数据对象，填充 部门名称字段
        for (SysFinancialExpenses record : records) {
            final Long deptId = record.getDeptId();
//            stream 是jdk8自带的方便操作集合的流，eg，对list元素进行分组，聚合，求最大值，最小值，等等，
//            几行代码就可以完成通过for循环传统操作几十行代码完成的功能
            final Optional<Department> first = departments.stream()
                    .filter(d -> Objects.equals(deptId, d.getId()))
                    .findFirst();

            SysFinancialExpensesVo one = new SysFinancialExpensesVo();
            BeanUtils.copyProperties(record, one);
//            如果 系统中不存在指定部门id的数据，就不填充部门名称，否则就填充（正常情况下会有的）
            if (first.isPresent()) {
                final String departmentName = first.get().getDepartmentName();
                one.setDeptName(departmentName);
            }
            sysFinancialExpensesVos.add(one);
        }

//        把填充好部门名称的数据塞到返回体里面，然后返回给前端
        sysFinancialExpensesVoIPage.setRecords(sysFinancialExpensesVos);
        return sysFinancialExpensesVoIPage;
    }
    /**
     * 上面代码等同于下面代码
     *              Department d=null;
     *             for (Department department : departments) {
     *                 Long departmentId = department.getId();
     *                 if (deptId==departmentId){
     *                     d=department;
     *                     break;
     *                 }
     *             }
     *             if (d!=null){
     *                 final String departmentName = d.getDepartmentName();
     *                 one.setDeptName(departmentName);
     *             }
     *
     */
    @Override
    public Boolean delete1(CommonReqVo commonReqVo) {
//        直接调用mybatis 的批量删除方法，删除数据
        return this.removeBatchByIds(commonReqVo.getMainIds());
    }

    @Override
    public Boolean save1(SysFinancialExpenses sysFinancialExpenses) {
//        之间调用 mybatis的 更新或者保存方法，进行更新或者保存
//        注意，根据主键id是否存在，以及主键id是否在数据库中存在来判断更新或者插入，
        return this.saveOrUpdate(sysFinancialExpenses);
    }

    @Override
    public List<SysFinancialExpensesVo> chart(CommonReqVo commonReqVo) {
        List<SysFinancialExpensesVo> charts = new ArrayList<>();
        // 查询财务支出信息，查询全部
        final List<SysFinancialExpenses> list = this.list();
        //如果没有查询到数据，则直接返回 ，不需要继续下面 数据转换为响应的数据结构 的逻辑处理
        if (CollectionUtils.isEmpty(list)) {
            return charts;
        }
        //数据库查询操作，将结果赋值给变量
        // 支出表中只有部门id并没有部门名称，界面上显示的是部门名称，所以需要先查询出部门信息数据，在根据部门id转换成部门名称
        final List<Department> departments = departmentMapper.selectList(null);
        // 将支出信息结果集合数据根据部门id分组，聚合每个部门内的薪水的数据
        for (Map.Entry<Long, List<SysFinancialExpenses>> longListEntry : list.stream()
                .collect(Collectors.groupingBy(SysFinancialExpenses::getDeptId))
                .entrySet()) {
            //部门id
            final Long deptId = longListEntry.getKey();
            // longListEntry.getValue() 根据部门id分组后的支出数据，可能有多个，然后映射出支出信息中的  Quantity字段，再求和
            final double sum = longListEntry.getValue()
                    .stream().mapToDouble(SysFinancialExpenses::getQuantity)
                    .sum();
            // 根本部门id 筛选出部门信息数据
            final Department department = departments.stream()
                    .filter(d -> Objects.equals(deptId, d.getId()))
                    .findFirst().get();
            //部门名称
            final String departmentName = department.getDepartmentName();
            //返回前端的响应内容
            SysFinancialExpensesVo one = new SysFinancialExpensesVo();
            one.setDeptId(deptId);
            one.setDeptName(departmentName);
            one.setQuantity(sum);
            charts.add(one);
        }

        return charts;
    }
}
